#include <sys/stat.h>
#include <time.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* lighttpd header file */
#include "log.h"
#include "base.h"
#include "first.h"
#include "array.h"
#include "buffer.h"
#include "plugin.h"
#include "response.h"
#include "http_chunk.h"
#include <hiredis/hiredis.h>


/**
 * this is a firstPlug for a lighttpd plugin
 *
 * just replaces every occurrence of 'firstPlug' by your plugin name
 *
 * e.g. in vim:
 *
 *   :%s/firstPlug/myhandler/
 *
 */



/* plugin config for all request/connections */

typedef struct {
    array *match;
} plugin_config;

typedef struct {
    PLUGIN_DATA;

    buffer *match_buf;

    plugin_config **config_storage;

    plugin_config conf;
} plugin_data;

typedef struct {
    size_t foo;
} handler_ctx;


void mydebug(char *debugInfo);

static handler_ctx * handler_ctx_init() {
    handler_ctx * hctx;

    hctx = calloc(1, sizeof(*hctx));

    return hctx;
}
handler_t firstPlug_handle_trigger(server *srv, void *p_d) {
    //log_error_write(srv,__FILE__, __LINE__,"test","firstPlug trigger","end", "endend");
    /*	FILE *fp = fopen("/tmp/test.txt","a+");
    	if(!fp)
    		return -1;
    	fprintf(fp,"test success\n");
    	fclose(fp);*/

    return HANDLER_GO_ON;
}

handler_t handlerURLClean(server *srv, connection *con, void *p_d) {
    FILE *fp = fopen("/tmp/test.txt", "a+");
    if(!fp) {
        log_error_write(srv, __FILE__, __LINE__, "first plugin", "handler url clean open file faild", "end", "end1");
        return HANDLER_GO_ON;
    }

    fprintf(fp, "connection info %s\n", con->request.uri->ptr);
    fclose(fp);
    return HANDLER_GO_ON;
}

static void handler_ctx_free(handler_ctx *hctx) {

    free(hctx);
}

/* init the plugin data */
INIT_FUNC(mod_firstPlug_init) {
    plugin_data *p;

    p = calloc(1, sizeof(*p));

    p->match_buf = buffer_init();

    return p;
}

/* destroy the plugin data */
FREE_FUNC(mod_firstPlug_free) {
    plugin_data *p = p_d;

    UNUSED(srv);

    if (!p) return HANDLER_GO_ON;

    if (p->config_storage) {
        size_t i;

        for (i = 0; i < srv->config_context->used; i++) {
            plugin_config *s = p->config_storage[i];

            if (NULL == s) continue;

            array_free(s->match);

            free(s);
        }
        free(p->config_storage);
    }

    buffer_free(p->match_buf);

    free(p);

    return HANDLER_GO_ON;
}

/* handle plugin config and check values */

SETDEFAULTS_FUNC(mod_firstPlug_set_defaults) {
    plugin_data *p = p_d;
    size_t i = 0;

    config_values_t cv[] = {
        { "firstPlug.array",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
        { NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
    };

    if (!p) return HANDLER_ERROR;

    p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));

    for (i = 0; i < srv->config_context->used; i++) {
        data_config const* config = (data_config const*)srv->config_context->data[i];
        plugin_config *s;

        s = calloc(1, sizeof(plugin_config));
        s->match    = array_init();

        cv[0].destination = s->match;

        p->config_storage[i] = s;

        if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
            return HANDLER_ERROR;
        }
    }

    return HANDLER_GO_ON;
}

#define PATCH(x) \
	p->conf.x = s->x;
static int mod_firstPlug_patch_connection(server *srv, connection *con, plugin_data *p) {
    size_t i, j;
    plugin_config *s = p->config_storage[0];

    PATCH(match);

    log_error_write(srv, __FILE__, __LINE__, "test", "patch_connection trigle", srv->tmp_buf->ptr);


    /* skip the first, the global context */
    for (i = 1; i < srv->config_context->used; i++) {
        data_config *dc = (data_config *)srv->config_context->data[i];
        s = p->config_storage[i];

        /* condition didn't match */
        if (!config_check_cond(srv, con, dc)) continue;

        /* merge config */
        for (j = 0; j < dc->value->used; j++) {
            data_unset *du = dc->value->data[j];

            if (buffer_is_equal_string(du->key, CONST_STR_LEN("firstPlug.array"))) {
                PATCH(match);
            }
        }
    }

    return 0;
}
#undef PATCH

int add(int m, int n) {
    return m + n;
}

int getKey(char *urlParam, char *key)
{
	if(!urlParam || !key)
		return -1;
	if( 1 != (sscanf(urlParam,"/?key=%s",key)))
		return -2;
	return 0;

}

void generateResult(char *szResult, char* key, char* value) {
    char tmpbuffer[200];

    sprintf(szResult,"<html>"

            "<head>"
            "<title> first html</title>"
            "</head>"

            "<body>"
            "<p> %s  => %s </p>"
            "</body>"

            "</html>", key, value);

}

void getvalue(char* key, char* value) {
    int timeout = 10000;
    struct timeval tv;
    tv.tv_sec = timeout / 1000;
    tv.tv_usec = timeout * 1000;
	FILE *fp = fopen("/tmp/redislog.txt", "a+");

    redisContext* c = redisConnect((char*)"127.0.0.1", 6379);
    if (c->err) {
		if(fp)
			fprintf(fp, "can't connect redis server\n");
        redisFree(c);
        return;
    }

    char command[1024];
    sprintf(command,"get %s",key);
    redisReply* r = (redisReply*)redisCommand(c,(const char*)command);

	if(NULL==r || r->type!=REDIS_REPLY_STRING)
	{
		if(fp)
		{
			fprintf(fp, "failed execute command %s\n", command);
		}
		redisFree(c);

	}
	else
	{
		strcpy(value,r->str);
	}

	if(fp)
		fclose(fp);

}
void mydebug(char *debugInfo)
{
	FILE *fp = fopen("/tmp/test.txt","a+");
	if(fp)
	{
		fprintf(fp,"debug info %s\n",debugInfo);
		fclose(fp);
	}
}
URIHANDLER_FUNC(mod_firstPlug_uri_handler) {
    plugin_data *p = p_d;
    size_t s_len;
    size_t k;
 
	UNUSED(srv);

    if (con->mode != DIRECT) return HANDLER_GO_ON;

    s_len = buffer_string_length(con->uri.path);
    if (0 == s_len) return HANDLER_GO_ON;

    mod_firstPlug_patch_connection(srv, con, p);

	char key[100],value[100];
    char szresult[3000];
    FILE *fp = fopen("/tmp/test.txt","a+");
    if(!fp) {
        log_error_write(srv, __FILE__, __LINE__, "test", "firstPlug can't open test.txt", "end", "end");
    } else {
        fprintf(fp,"conneciton info %s\n", con->request.uri->ptr);
        fclose(fp);
    }

    int params[2];
	if( 0 != getKey(con->request.uri->ptr,key))
	{
		return HANDLER_GO_ON;
	}
	else
	{
		con->mode = 3;
		value[0] = '\0';
		getvalue(key,value);
		if(0 == strlen(value))
		{
			log_error_write(srv, __FILE__, __LINE__, "test", "can't get value:redis", "end", "end");
		}
	}
	char debugBuffer[100];
	sprintf(debugBuffer, "key:%s,value:%s",key,value);
    generateResult(szresult,key, value);
    char *append= szresult;
    int len = strlen(append) + 1;
    http_chunk_append_mem(srv, con, append, len);
    con->file_finished = 1;
    return HANDLER_GO_ON;

    for (k = 0; k < p->conf.match->used; k++) {
        data_string *ds = (data_string *)p->conf.match->data[k];
        size_t ct_len = buffer_string_length(ds->value);

        if (ct_len > s_len) continue;
        if (ct_len == 0) continue;

        if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
            con->http_status = 403;

            return HANDLER_FINISHED;
        }
    }

    /* not found */
    return HANDLER_GO_ON;
}


/* this function is called at dlopen() time and inits the callbacks */

int mod_firstPlug_plugin_init(plugin *p) {
    p->version     = LIGHTTPD_VERSION_ID;
    p->name        = buffer_init_string("firstPlug");

    p->init        = mod_firstPlug_init;
    p->handle_uri_clean  = mod_firstPlug_uri_handler;
    p->set_defaults  = mod_firstPlug_set_defaults;
    p->cleanup     = mod_firstPlug_free;
//	p->handle_trigger = firstPlug_handle_trigger;
    p->data        = NULL;
    //p->handle_uri_clean = handlerURLClean;
    return 0;
}
